package com.it.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.it.bean.Quartz;
import com.it.mapper.QuartzMapper;
import com.it.page.PageQuery;
import com.it.service.QuartzService;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.quartz.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * @author TBH
 * @date 2025-05-19 15:34:22
 * @desc
 */
@Service("quartzService")
@RequiredArgsConstructor
public class QuartzServiceImpl implements QuartzService {

    private final QuartzMapper quartzMapper;

    private static final String STATUS_NORMAL = "1";
    public static final String STATUS_DISABLE = "0";

    private final Scheduler scheduler;

    /**
     * 立即执行的任务分组
     */
    private static final String JOB_GROUP = "infrastructure_group";

    /**
     * 保存&启动定时任务
     */
    @Override
    public void saveAndScheduleJob(Quartz quartzJob) {
        int insert = quartzMapper.insert(quartzJob);
        if (insert > 0) {
            if (Objects.equals(STATUS_NORMAL, quartzJob.getStatus())) {
                // 定时器添加
                this.schedulerAdd(String.valueOf(quartzJob.getId()), quartzJob.getJob().trim(), quartzJob.getCron().trim(), quartzJob.getParams());
            }
        }
    }

    /**
     * 恢复定时任务
     */
    @Override
    public void resumeJob(Long id) {
        Quartz quartz = quartzMapper.selectByPrimaryKey(id);
        schedulerDelete(String.valueOf(quartz.getId()));
        schedulerAdd(String.valueOf(quartz.getId()), quartz.getJob().trim(), quartz.getCron().trim(), quartz.getParams());
        quartz.setStatus(STATUS_NORMAL);
        quartzMapper.updateByPrimaryKeySelective(quartz);
    }

    /**
     * 编辑&启停定时任务
     *
     * @throws SchedulerException 定时任务启动错误
     */
    @Override
    public void editAndScheduleJob(Quartz quartzJob) throws SchedulerException {
        if (STATUS_NORMAL.equals(quartzJob.getStatus())) {
            schedulerDelete(String.valueOf(quartzJob.getId()));
            schedulerAdd(String.valueOf(quartzJob.getId()), quartzJob.getJob().trim(), quartzJob.getCron().trim(), quartzJob.getParams());
        } else {
            scheduler.pauseJob(JobKey.jobKey(String.valueOf(quartzJob.getId())));
        }
        quartzMapper.updateByPrimaryKeySelective(quartzJob);
    }

    /**
     * 删除&停止删除定时任务
     */
    @Override
    public void deleteAndStopJob(Long id) {
        schedulerDelete(String.valueOf(id));
        quartzMapper.deleteByPrimaryKey(id);
    }

    @Override
    public void execute(Long id) throws Exception {
        Quartz quartz = quartzMapper.selectByPrimaryKey(id);
        String jobName = quartz.getJob().trim();
        Date startDate = new Date();
        String identity = jobName + quartz.getId();
        startDate.setTime(startDate.getTime() + 100L);
        SimpleTrigger trigger = (SimpleTrigger) TriggerBuilder.newTrigger()
                .withIdentity(identity, JOB_GROUP)
                .startAt(startDate)
                .build();
        JobDetail jobDetail = JobBuilder.newJob(getClass(jobName).getClass()).withIdentity(identity).usingJobData("params", quartz.getParams()).build();
        scheduler.scheduleJob(jobDetail, trigger);
        scheduler.start();
    }

    @Override
    public void pause(Long id) throws SchedulerException {
        Quartz quartz = quartzMapper.selectByPrimaryKey(id);
        if (scheduler.checkExists(JobKey.jobKey(String.valueOf(id)))) {
            schedulerDelete(String.valueOf(id));
        }
        quartz.setStatus(STATUS_DISABLE);
        quartzMapper.updateByPrimaryKeySelective(quartz);
    }

    @Override
    public List<Quartz> findAllStart() {
        Example example = new Example(Quartz.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("status", "1");
        return quartzMapper.selectByExample(example);
    }

    @Override
    public PageInfo<Quartz> page(PageQuery<Quartz> pageQuery) {
        PageHelper.startPage(pageQuery.getPage(), pageQuery.getPageSize());
        Quartz queryBody = pageQuery.getQueryBody();
        Example example = new Example(Quartz.class);
        Example.Criteria criteria = example.createCriteria();
        if (Objects.nonNull(queryBody) && StringUtils.isNotEmpty(queryBody.getJob())) {
            criteria.andEqualTo("job", queryBody.getJob());
        }
        if (Objects.nonNull(queryBody) && StringUtils.isNotEmpty(queryBody.getStatus())) {
            criteria.andEqualTo("status", queryBody.getStatus());
        }
        List<Quartz> quartz = quartzMapper.selectByExample(example);
        return new PageInfo<>(quartz);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void save(Quartz quartz) throws SchedulerException {
        if (Objects.nonNull(quartz.getId())) {
            editAndScheduleJob(quartz);
        } else {
            saveAndScheduleJob(quartz);
        }
    }

    @Override
    public void delete(Long id) {
        deleteAndStopJob(id);
    }

    @Override
    public void resume(Long id) {
        resumeJob(id);
    }

    /**
     * 添加定时任务
     *
     * @param job    全限定类名
     * @param cron   表达式错误
     * @param params 参数
     */
    private void schedulerAdd(String id, String job, String cron, String params) {
        try {
            // 启动调度器
            scheduler.start();
            // 构建job信息
            JobDetail jobDetail = JobBuilder.newJob(getClass(job).getClass()).withIdentity(id).usingJobData("params", params).build();
            // 表达式调度构建器(即任务执行的时间)
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cron);
            // 按新的cronExpression表达式构建一个新的trigger
            CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(id).withSchedule(scheduleBuilder).build();
            scheduler.scheduleJob(jobDetail, trigger);
        } catch (SchedulerException e) {
            throw new RuntimeException("创建定时任务失败", e);
        } catch (RuntimeException e) {
            throw new RuntimeException(e.getMessage(), e);
        } catch (Exception e) {
            throw new RuntimeException("后台找不到该类名：" + job, e);
        }
    }

    /**
     * 删除定时任务
     *
     * @param id 定时任务id
     */
    private void schedulerDelete(String id) {
        try {
            scheduler.pauseTrigger(TriggerKey.triggerKey(id));
            scheduler.unscheduleJob(TriggerKey.triggerKey(id));
            scheduler.deleteJob(JobKey.jobKey(id));
        } catch (Exception e) {
            throw new RuntimeException("删除定时任务失败");
        }
    }

    private static Job getClass(String job) throws Exception {
        Class<?> clazz = Class.forName(job);
        return (Job) clazz.newInstance();
    }

    @PostConstruct
    public void initJobs() throws SchedulerException {
        scheduler.clear();
        List<Quartz> jobs = findAllStart();
        jobs.forEach(job -> {
            if (STATUS_NORMAL.equals(job.getStatus())) {
                schedulerAdd(String.valueOf(job.getId()), job.getJob(), job.getCron(), job.getParams());
            }
        });
    }

    @PreDestroy
    public void shutdown() throws SchedulerException {
        scheduler.standby(); // 优雅停止
    }
}